import {next} from "lodash/seq";
import {nextTick} from "../util/next-tick";
import {isDef} from "../../shared/util";

class Scheduler {

    constructor () {
        // 渲染的 watcher 队列
        this.queue = [];
        // 状态 正在渲染
        this.flushing = false;

        // fixme 这个现在貌似还没用 ？？？？
        // 状态 正在等待，没有渲染
        this.waiting = false;

        // 每个 Watcher 在本次渲染运行的次数
        this.circular = {};
        // 每个 Watcher 最大的渲染次数
        this.MAX_UPDATE = 100;
    }

    /**
     * 重置调度器
     */
    resetScheduler () {
        // 清空渲染队列
        this.queue.length = 0;
        // 状态 正在渲染
        this.flushing = false;
        // Watcher 渲染次数记录
        this.circular = {};
    }

    /**
     * 根据 queue 中的 watcher, 清空渲染队列
     */
    flushQueue () {
        // 根据 watcher id 进行排序，从小到大排序
        // 从小到大排序是因为 父组件的 watcher 先于子组件 watcher 生成
        // 父组件 watcher id 小于 子组件 watcher id
        this.queue.sort((a, b) => { return (a.id - b.id) });
        // 渲染标志 置 true
        this.flushing = true;
        // 根据 queue 中的 watcher 进行更新
        while (isDef(this.queue[0])) {
            // 获取第一个 watcher
            const watcher = this.queue[0];
            const watcherId = watcher.id;
            // 判断是否存在循环更新逻辑，如果正常，则调用 update 方法
            this.circular[watcherId] = (this.circular[watcherId] || 0) + 1;
            if (this.circular[watcherId] <= this.MAX_UPDATE) {
                watcher.updateImmediate();
            }
            // 将调用过 update 的 watcher 从 queue 中移除
            this.queue.splice(0, 1);
        }
        // 渲染结束，渲染标志置 false
        this.flushing = false;
        // 重置调度器
        this.resetScheduler();
    }

    /**
     * 向渲染队列中推入 watcher
     * @param {Watcher} watcher
     */
    pushWatcher (watcher) {
        // 如果不在渲染中, 直接添加
        if (!this.flushing) {
            this.queue.push(watcher);
        }
        // 如果在渲染中, 按照 watcherId 进行添加
        else {
            const watcherId = watcher.id;
            for (let i=0; i<this.queue.length ; i++) {
                if (this.queue[i].id >= watcherId) {
                    this.queue.splice(i + 1, 0, watcher);
                }
            }
        }
        // 如果不在刷新，调用 flushQueue
        if (!this.flushing) {
            nextTick(scheduler.flushQueue, scheduler)
        }
    }

}

const scheduler = new Scheduler();

/**
 *
 * @param {Watcher} watcher
 */
export function queueWatcher (watcher) {
    scheduler.pushWatcher(watcher);
}
